let toolTip;
let waitTip;
class AnalysisTools {
  constructor(viewer) {
    if (!viewer) throw new Error("no viewer object!");
    this.viewer = viewer;
    this.handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
    // 可视域分析--START
    let canvasEle = document.getElementById("viewershed");
    if (!canvasEle) {
      canvasEle = document.createElement("canvas");
      canvasEle.setAttribute("id", "viewershed");
      canvasEle.setAttribute("style", "display:none");
      document.body.appendChild(canvasEle);
    }
    this.canvasEle = canvasEle;
    this.lightCamera;
    this.pyramid;
    this.frustumPrimitive;
    this.viewershedPolygon;
    this.ViewShedOptions;
    // 可视域分析--END

    // 通视分析--START
    this.resultObject = {
      viewPoint: undefined, //通视分析起点
      targetPoints: [], //通视分析目标点集合
      targetPoint: undefined, //当前目标点
      objectExclude: [], //射线排除集合
      entities: [], //创建的Entity对象
    };
    // 通视分析--END

    // 坡度分析--START
    this.result = []; //存储创建的坡度分析结果，primitive集合
    this.arrowWidth;
    // 坡度分析--END
  }
  //全局清除
  clearAll() {
    this.clearSlopeAll();
    this.clearViewershedAll();
    this.clearVisibility();
  }

  //初始化监听事件
  initHandler() {
    if (this.handler) {
      this.handler.destroy();
      this.handler = undefined;
    }
  }

  //-------------坡向分析-------------------STRAT-------------

  //等距离切分网格
  createNew4Distance(distance) {
    distance = distance || 0.1; //默认0.1km精度
    let width = distance * 200 > 35 ? 35 : distance * 200;
    this.arrowWidth = width < 15 ? 15 : width;
    const viewer = this.viewer;
    CreatePolygonOnGround(
      viewer,
      [],
      {
        color: Cesium.Color.RED.withAlpha(0.1),
        outlineColor: Cesium.Color.YELLOW,
        outlineWidth: 2,
      },
      (polygon) => {
        let degrees = Cartesian3ListToWGS84(polygon.pottingPoint);
        viewer.entities.remove(polygon);
        let boundary = [];
        let minX = 10000,
          minY = 10000,
          maxX = -10000,
          maxY = -1000;
        for (let index = 0; index < degrees.length; index++) {
          const element = degrees[index];
          const x = element.lng;
          const y = element.lat;
          boundary.push([x, y]);
          minX = x < minX ? x : minX;
          minY = y < minY ? y : minY;
          maxX = x > maxX ? x : maxX;
          maxY = y > maxY ? y : maxY;
        }
        boundary.push(boundary[0]);
        let bbox = [minX, minY, maxX, maxY];
        let mask = turf.polygon([boundary]);
        let gridSquare = turf.squareGrid(bbox, distance, {
          mask: mask,
        });
        this.createEllipse(gridSquare);
      }
    );
  }
  // 等分切分网格，切分成一个num*num的网格
  createNew4Num(num) {
    return new Promise((resolve, reject) => {
      const viewer = this.viewer;
      CreatePolygonOnGround(
        viewer,
        [],
        {
          color: Cesium.Color.RED.withAlpha(0.1),
          outlineColor: Cesium.Color.YELLOW,
          outlineWidth: 2,
        },
        (polygon) => {
          let degrees = Cartesian3ListToWGS84(polygon.pottingPoint);
          viewer.entities.remove(polygon);
          let boundary = [];
          let minX = 10000,
            minY = 10000,
            maxX = -10000,
            maxY = -1000;

          for (let index = 0; index < degrees.length; index++) {
            const element = degrees[index];
            const x = element.lng;
            const y = element.lat;
            boundary.push([x, y]);
            minX = x < minX ? x : minX;
            minY = y < minY ? y : minY;
            maxX = x > maxX ? x : maxX;
            maxY = y > maxY ? y : maxY;
          }

          boundary.push(boundary[0]);
          let bbox = [minX, minY, maxX, maxY];
          let a = maxX - minX;
          let b = maxY - minY;
          b = b > a ? b : a;
          const step = b / num;
          let width = step * 2000 > 35 ? 35 : step * 2000;
          this.arrowWidth = width < 15 ? 15 : width;
          let mask = turf.polygon([boundary]);
          let gridSquare = turf.squareGrid(bbox, step, {
            units: "degrees",
            mask: mask,
          });
          this.createEllipse(gridSquare);
          resolve();
        }
      );
    });
  }
  createEllipse(gridSquare) {
    let boxResults = [];
    for (let index = 0; index < gridSquare.features.length; index++) {
      const feature = gridSquare.features[index];
      const coordinates = feature.geometry.coordinates[0];
      const centerdegree = [
        (coordinates[0][0] + coordinates[2][0]) / 2,
        (coordinates[0][1] + coordinates[2][1]) / 2,
      ];
      let centerCartographic = Cesium.Cartographic.fromDegrees(
        centerdegree[0],
        centerdegree[1]
      );
      boxResults.push(centerCartographic);
      for (let i = 0; i < coordinates.length; i++) {
        const coord = coordinates[i];
        let cartographic = Cesium.Cartographic.fromDegrees(coord[0], coord[1]);
        boxResults.push(cartographic);
        const coord1 = coordinates[i + 1];
        if (coord1) {
          let newCoord = [
            (coord[0] + coord1[0]) / 2,
            (coord[1] + coord1[1]) / 2,
          ];
          let newCartographic = Cesium.Cartographic.fromDegrees(
            newCoord[0],
            newCoord[1]
          );
          boxResults.push(newCartographic);
        }
      }
    }
    Cesium.sampleTerrainMostDetailed(
      this.viewer.scene.terrainProvider,
      boxResults
    ).then((updatePositions) => {
      let arrr = [];
      let ellipseResults = updatePositions.reduce(function (
        pre,
        item,
        index,
        updatePositions
      ) {
        var begin = index * 10;
        var end = begin + 10;
        var res = updatePositions.slice(begin, end);
        if (res.length != 0) {
          arrr[index] = res;
        }
        return arrr;
      },
      []);
      this.calculateSlope(ellipseResults);

      if (waitTip) {
        console.log(waitTip, "waitTip");

        waitTip.close();
      }
    });
  }

  createPolygonInsrance(points, color) {
    let positions = [];
    for (let index = 1; index < points.length - 1; index++) {
      const element = points[index];
      positions.push(Cesium.Cartographic.toCartesian(element));
    }
    let polygon = new Cesium.PolygonGeometry({
      polygonHierarchy: new Cesium.PolygonHierarchy(positions),
    });

    let polygonInstance = new Cesium.GeometryInstance({
      geometry: polygon,
      attributes: {
        color: Cesium.ColorGeometryInstanceAttribute.fromColor(
          Cesium.Color.fromCssColorString(color)
        ),
        show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏
      },
    });
    return polygonInstance;
  }
  createArrowInstance(
    targetPoint,
    center,
    diagonalPoint,
    heightDifference,
    curSlope
  ) {
    let cartographic_0 = new Cesium.Cartographic(
      (targetPoint.longitude + center.longitude) / 2,
      (targetPoint.latitude + center.latitude) / 2,
      (targetPoint.height + center.height) / 2
    );
    let cartographic_1 = new Cesium.Cartographic(
      (diagonalPoint.longitude + center.longitude) / 2,
      (diagonalPoint.latitude + center.latitude) / 2,
      (diagonalPoint.height + center.height) / 2
    );
    //偏移的
    let positions1 =
      heightDifference > 0
        ? [
            Cesium.Cartographic.toCartesian(cartographic_0),
            Cesium.Cartographic.toCartesian(cartographic_1),
          ]
        : [
            Cesium.Cartographic.toCartesian(cartographic_1),
            Cesium.Cartographic.toCartesian(cartographic_0),
          ];
    //箭头线
    const instance = new Cesium.GeometryInstance({
      id: {
        type: "SlopeAspect",
        value: curSlope,
      },
      geometry: new Cesium.GroundPolylineGeometry({
        positions: positions1,
        width: this.arrowWidth,
      }),
      attributes: {
        color: Cesium.ColorGeometryInstanceAttribute.fromColor(
          Cesium.Color.BLUE.withAlpha(0.6)
        ),
        show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏
      },
    });
    return instance;
  }
  calculateSlope(ellipseResults) {
    let instances = [];
    let polygonInstance = [];
    for (let index = 0; index < ellipseResults.length; index++) {
      const ellipse = ellipseResults[index];

      const center = ellipse[0];
      let heightDifference = 0;
      let maxIndex = 0;
      for (let i = 1; i < ellipse.length - 1; i++) {
        const point = ellipse[i];
        let curHD = point.height - center.height;
        if (Math.abs(curHD) > heightDifference) {
          heightDifference = curHD;
          maxIndex = i;
        }
      }
      let pos0 = new Cesium.Cartographic(center.longitude, center.latitude, 0);
      let pos1 = new Cesium.Cartographic(
        ellipse[maxIndex].longitude,
        ellipse[maxIndex].latitude,
        0
      );
      let distance = Cesium.Cartesian3.distance(
        Cesium.Cartographic.toCartesian(pos0),
        Cesium.Cartographic.toCartesian(pos1)
      );
      let curSlope = Math.abs(heightDifference / distance); //坡度的tan值
      let curColor = this.calculateSlopeColor(curSlope, 1);
      const curPolygonInstance = this.createPolygonInsrance(ellipse, curColor);
      polygonInstance.push(curPolygonInstance);

      let diagonalPoint =
        maxIndex > 4 ? ellipse[maxIndex - 4] : ellipse[maxIndex + 4]; //对角点
      let targetPoint = ellipse[maxIndex];
      const arrowInstance = this.createArrowInstance(
        targetPoint,
        center,
        diagonalPoint,
        heightDifference,
        curSlope
      );
      instances.push(arrowInstance);
    }
    const mapPrimitive = this.viewer.scene.primitives.add(
      new Cesium.GroundPrimitive({
        geometryInstances: polygonInstance,
        appearance: new Cesium.PerInstanceColorAppearance({
          translucent: true, //false时透明度无效
          closed: false,
        }),
      })
    );
    const arrowPrimitive = this.viewer.scene.primitives.add(
      new Cesium.GroundPolylinePrimitive({
        geometryInstances: instances,
        appearance: new Cesium.PolylineMaterialAppearance({
          material: new Cesium.Material({
            fabric: {
              type: "PolylineArrow",
              uniforms: {
                color: new Cesium.Color(1.0, 1.0, 0.0, 0.8),
              },
            },
          }),
        }),
      })
    );
    this.result.push(arrowPrimitive, mapPrimitive);
  }
  clearSlopeAll() {
    this.result.forEach((element) => {
      this.viewer.scene.primitives.remove(element);
    });
    this.result = [];
  }
  //根据坡度值赋值颜色
  calculateSlopeColor(value, alpha) {
    // 0°～0.5°为平原0.00872686779075879,rgb(85,182,43)
    // 0.5°～2°为微斜坡0.03492076949174773,rgb(135,211,43)
    // 2°～5°为缓斜坡0.08748866352592401,rgb(204,244,44)
    // 5°～15°为斜坡0.2679491924311227,rgb(245,233,44)
    // 15°～35°为陡坡0.7002075382097097,rgb(255,138,43)
    // 35°～55°为峭坡1.4281480067421144,rgb(255,84,43)
    // 55°～90°为垂直壁,rgb(255,32,43)
    if (value < 0.00872686779075879) {
      return "rgba(85,182,43," + alpha + ")";
    } else if (value < 0.03492076949174773) {
      return "rgba(135,211,43," + alpha + ")";
    } else if (value < 0.08748866352592401) {
      return "rgba(204,244,44," + alpha + ")";
    } else if (value < 0.2679491924311227) {
      return "rgba(245,233,44," + alpha + ")";
    } else if (value < 0.7002075382097097) {
      return "rgba(255,138,43," + alpha + ")";
    } else if (value < 1.4281480067421144) {
      return "rgba(255,84,43," + alpha + ")";
    } else {
      return "rgba(255,32,43," + alpha + ")";
    }
  }

  //-------------坡向分析-------------------END-------------

  //-------------通视分析-------------------STRAT-------------

  stratVisibility() {
    toolTip = "左键点击创建视角起点";
    this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.canvas);
    this.handler.setInputAction((event) => {
      let cartesian = getCatesian3FromPX(this.viewer, event.position);
      let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
      cartographic.height += 1.8;
      cartesian = Cesium.Cartesian3.fromRadians(
        cartographic.longitude,
        cartographic.latitude,
        cartographic.height
      );
      // console.log(cartographic,'++++++++++++');

      toolTip = "左键创建视角终点，右键结束通视分析";
      if (cartesian) {
        if (!this.resultObject.viewPoint) {
          this.resultObject.viewPoint = cartesian;
          let pointEntity = this.viewer.entities.add({
            position: cartesian,
            point: {
              color: Cesium.Color.YELLOW,
              pixelSize: 5,
            },
            label: {
              text: "视角源点",
              font: "bold 20px KaiTi",
              fillColor: Cesium.Color.YELLOW,
              pixelOffset: new Cesium.Cartesian2(0, -20),
            },
          });
          this.resultObject.objectExclude.push(pointEntity);
          this.resultObject.entities.push(pointEntity);
        } else {
          this.resultObject.targetPoint = cartesian;
          let pointEntity = this.viewer.entities.add({
            position: cartesian,
            point: {
              color: Cesium.Color.YELLOW,
              pixelSize: 5,
            },
            label: {
              text: "目标点",
              font: "bold 20px KaiTi",
              fillColor: Cesium.Color.RED,
              pixelOffset: new Cesium.Cartesian2(0, -20),
            },
          });
          this.resultObject.objectExclude.push(pointEntity);
          this.resultObject.entities.push(pointEntity);
          let direction = Cesium.Cartesian3.normalize(
            Cesium.Cartesian3.subtract(
              this.resultObject.targetPoint,
              this.resultObject.viewPoint,
              new Cesium.Cartesian3()
            ),
            new Cesium.Cartesian3()
          );

          let ray = new Cesium.Ray(this.resultObject.viewPoint, direction);
          let result = this.viewer.scene.pickFromRay(
            ray,
            this.resultObject.objectExclude
          ); // 计算交互点，返回第一个
          if (result) {
            let dis0 = this.distance(
              this.resultObject.viewPoint,
              this.resultObject.targetPoint
            );
            let dis1 = this.distance(
              this.resultObject.viewPoint,
              result.position
            );
            let dis2 = this.distance(
              result.position,
              this.resultObject.targetPoint
            );
            // console.log(dis0, dis1, dis2);
            if (dis0 > dis1) {
              let _poly0 = this.viewer.entities.add({
                polyline: {
                  positions: [this.resultObject.viewPoint, result.position],
                  material: Cesium.Color.GREEN,
                  width: 3,
                },
              });
              this.resultObject.entities.push(_poly0);
              let _poly1 = this.viewer.entities.add({
                polyline: {
                  positions: [result.position, this.resultObject.targetPoint],
                  material: Cesium.Color.RED,
                  width: 3,
                },
              });
              this.resultObject.entities.push(_poly1);
              this.resultObject.targetPoints.push({
                targetPoint: cartesian,
                visual: false, //如果dis2足够小，其实他是可视的
                distance: [dis0, dis1, dis2], //[初始点和终点，初始点和交点，交点和终点]
              });
            } else {
              let _poly2 = this.viewer.entities.add({
                polyline: {
                  positions: [
                    this.resultObject.viewPoint,
                    this.resultObject.targetPoint,
                  ],
                  material: Cesium.Color.GREEN,
                  width: 3,
                },
              });
              this.resultObject.entities.push(_poly2);
              this.resultObject.targetPoints.push({
                targetPoint: cartesian,
                visual: true, //如果dis2足够小，其实他是可视的
                distance: [dis0, dis1, dis2], //[初始点和终点，初始点和交点，交点和终点]
              });
            }
          }
        }
      }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    this.handler.setInputAction(function (move) {
      CreateRemindertip(toolTip, move.endPosition, true);
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    this.handler.setInputAction((event) => {
      CreateRemindertip(toolTip, event.endPosition, false);
      this.handler.destroy();
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
  }
  clearVisibility() {
    this.resultObject.entities.forEach((element) => {
      this.viewer.entities.remove(element);
    });
    // --start--（新增代码）此处代码是为了在点击其他分析功能的时候做排异处理，在清空操作中释放事件（）
    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    if (toolTip) {
      CreateRemindertip(toolTip, { x: 0, y: 0 }, false);
    }
    // --ending--
    this.resultObject = {
      viewPoint: undefined, //通视分析起点
      targetPoints: [], //通视分析目标点集合
      targetPoint: undefined, //当前目标点
      objectExclude: [], //射线排除集合
      entities: [], //创建的Entity对象
    };
  }
  //空间两点间距离
  distance(point1, point2) {
    let point1cartographic = Cesium.Cartographic.fromCartesian(point1);
    let point2cartographic = Cesium.Cartographic.fromCartesian(point2);
    /**根据经纬度计算出距离**/
    let geodesic = new Cesium.EllipsoidGeodesic();
    geodesic.setEndPoints(point1cartographic, point2cartographic);
    let s = geodesic.surfaceDistance;
    //返回两点之间的距离
    s = Math.sqrt(
      Math.pow(s, 2) +
        Math.pow(point2cartographic.height - point1cartographic.height, 2)
    );
    return s;
  }

  //-------------通视分析-------------------END-------------

  //--------可视域分析-START--------------------------------------------
  /**
	 * 带参数加载分析结果
	 * @param {number} precision 精度，值越大创建耗时越长，建议在10~20之间
	 * @param {object} {
	   viewPosition: null, //观测点 笛卡尔坐标
	   endPosition: null, //目标点 笛卡尔坐标
		direction: 0, //观测方位角 默认为`0`,范围`0~360`
		pitch: 0, //俯仰角,radius,默认为`0`
		horizontalViewAngle: 90, //可视域水平夹角,默认为 `90`,范围`0~360`
		verticalViewAngle: 60, //可视域垂直夹角,默认为`60`,范围`0~180`
		visibleColor: "#0000ff80", //可视区域颜色,16进制颜色+两位透明度
		invisibleColor: "#ff000080", //bu可视区域颜色,16进制颜色+两位透明度

	 } 精度，值越大创建耗时越长，建议在10~20之间
	 */
  initViewshed(precision = 20, options = {}) {
    return new Promise((resolve, reject) => {
      let _options = {
        viewPosition: null, //观测点 笛卡尔坐标
        endPosition: null, //目标点 笛卡尔坐标
        direction: 0, //观测方位角 默认为`0`,范围`0~360`
        pitch: 0, //俯仰角,radius,默认为`0`
        horizontalViewAngle: 90, //可视域水平夹角,默认为 `90`,范围`0~360`
        verticalViewAngle: 60, //可视域垂直夹角,默认为`60`,范围`0~180`
        visualRange: 100, //距离,单位`米`
      };
      this.ViewShedOptions = Object.assign(_options, options);

      // console.log(this.ViewShedOptions)
      this.setLightCamera();
      this.addVisualPyramid();
      this.createFrustum();
      // console.time()
      let res = this.drawViewershed(precision, options);
      // console.timeEnd()
      resolve(res);
    });
  }
  /**
	 * 开始执行视域分析
	 * @param {number} precision 精度，值越大创建耗时越长，建议在10~20之间
	 * @param {object} {
		direction: 0, //观测方位角 默认为`0`,范围`0~360`
		pitch: 0, //俯仰角,radius,默认为`0`
		horizontalViewAngle: 90, //可视域水平夹角,默认为 `90`,范围`0~360`
		verticalViewAngle: 60, //可视域垂直夹角,默认为`60`,范围`0~180`
		visibleColor: "#0000ff80", //可视区域颜色,16进制颜色+两位透明度
		invisibleColor: "#ff000080", //bu可视区域颜色,16进制颜色+两位透明度

	 } 精度，值越大创建耗时越长，建议在10~20之间
	 */
  createViewshed(precision = 20, opts = {}) {
    return new Promise((resolve, reject) => {
      this.initHandler();
      this.clearViewershedAll();
      let scene = this.viewer.scene;
      let tip;
      this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.canvas);

      this.handler.setInputAction((event) => {
        // 禁止地球旋转和缩放，地球的旋转会对鼠标移动监听有影响，所以需要禁止
        scene.screenSpaceCameraController.enableRotate = false;
        scene.screenSpaceCameraController.enableZoom = false;
        scene.globe.depthTestAgainstTerrain = true;

        let earthPosition = scene.pickPosition(event.position);
        let ellipsoid = this.viewer.scene.globe.ellipsoid;
        let cartographic = ellipsoid.cartesianToCartographic(earthPosition);
        cartographic.height = cartographic.height + 1.8; // 获取高度+附加高度
        earthPosition = ellipsoid.cartographicToCartesian(cartographic);

        let pos = this.cartesian3ToDegree(earthPosition);
        this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);

        this.handler.setInputAction((event) => {
          let newPosition = scene.pickPosition(event.endPosition);
          tip = CreateRemindertip("右键完成分析", event.endPosition, true);

          if (Cesium.defined(newPosition)) {
            let pos1 = this.cartesian3ToDegree(newPosition);
            // console.log(newPosition, earthPosition)
            let distance = Cesium.Cartesian3.distance(
              newPosition,
              earthPosition
            );
            let angle = this.getAngle(pos[0], pos[1], pos1[0], pos1[1]);
            let pitch = this.getPitch(earthPosition, newPosition);

            let _viewShedOptions = {
              viewPosition: earthPosition, //观测点 笛卡尔坐标
              endPosition: newPosition, //目标点 笛卡尔坐标
              direction: opts.direction || angle, //观测方位角 默认为`0`,范围`0~360`
              pitch: opts.pitch || pitch, //俯仰角,radius,默认为`0`
              horizontalViewAngle: opts.horizontalViewAngle || 90, //可视域水平夹角,默认为 `90`,范围`0~360`
              verticalViewAngle: opts.verticalViewAngle || 60, //可视域垂直夹角,默认为`60`,范围`0~180`
              visibleAreaColor: opts.visibleColor || Cesium.Color.GREEN, //可视区域颜色,默认为`green`
              invisibleAreaColor: opts.invisibleColor || Cesium.Color.RED, //不可见区域颜色,默认为`red`
              visualRange: opts.visualRange || distance, //距离,单位`米`
            };
            // console.log(_viewShedOptions);

            // this.ViewShedOptions = Object.assign(_viewShedOptions, opts)
            this.ViewShedOptions = _viewShedOptions;
            this.updateViewShed();
            // CreateRemindertip("右键完成分析", event.endPosition, false);
            // console.log(tip,'tip');
          }
        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

      this.handler.setInputAction((event) => {
        this.ViewShedOptions.endPosition = scene.pickPosition(event.position);
        this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
        this.initHandler();
        // 开启地球旋转和缩放
        scene.screenSpaceCameraController.enableRotate = true;
        scene.screenSpaceCameraController.enableZoom = true;
        // console.log(this.ViewShedOptions)
        // console.time()
        let res = this.drawViewershed(precision, opts);
        // console.timeEnd()
        tip.show(false);
        resolve(res);
      }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    });
  }
  ReturnDistance(pos0, pos1) {
    let distance = 0;
    let point1cartographic = Cesium.Cartographic.fromCartesian(pos0);
    let point2cartographic = Cesium.Cartographic.fromCartesian(pos1);
    /**根据经纬度计算出距离**/
    let geodesic = new Cesium.EllipsoidGeodesic();
    geodesic.setEndPoints(point1cartographic, point2cartographic);
    let s = geodesic.surfaceDistance;
    return s;
  }
  getHeight(x, y, objectsToExclude) {
    let endCartographic = Cesium.Cartographic.fromDegrees(x, y);
    let endHeight = this.viewer.scene.sampleHeight(
      endCartographic,
      objectsToExclude
    );
    return endHeight;
  }

  cartesian3ToDegree(Cartesian3) {
    let _ellipsoid = this.viewer.scene.globe.ellipsoid;
    let _cartographic = _ellipsoid.cartesianToCartographic(Cartesian3);
    let _lat = Cesium.Math.toDegrees(_cartographic.latitude);
    let _lng = Cesium.Math.toDegrees(_cartographic.longitude);
    let _alt = _cartographic.height;
    return [_lng, _lat, _alt];
  }
  getAngle(lng1, lat1, lng2, lat2) {
    let dRotateAngle = Math.atan2(Math.abs(lng1 - lng2), Math.abs(lat1 - lat2));
    if (lng2 >= lng1) {
      dRotateAngle = lat2 < lat1 ? Math.PI - dRotateAngle : dRotateAngle;
    } else {
      dRotateAngle =
        lat2 >= lat1 ? 2 * Math.PI - dRotateAngle : Math.PI + dRotateAngle;
    }
    dRotateAngle = (dRotateAngle * 180) / Math.PI;
    return dRotateAngle;
  }

  getPitch(pointA, pointB) {
    let transfrom = Cesium.Transforms.eastNorthUpToFixedFrame(pointA);
    const vector = Cesium.Cartesian3.subtract(
      pointB,
      pointA,
      new Cesium.Cartesian3()
    );
    let direction = Cesium.Matrix4.multiplyByPointAsVector(
      Cesium.Matrix4.inverse(transfrom, transfrom),
      vector,
      vector
    );
    Cesium.Cartesian3.normalize(direction, direction);
    return Cesium.Math.PI_OVER_TWO - Cesium.Math.acosClamped(direction.z);
  }
  updateViewShed() {
    this.clearViewShed();
    this.setLightCamera();
    this.addVisualPyramid();
    this.createFrustum();
  }
  clearViewShed() {
    if (this.pyramid) {
      this.viewer.entities.removeById(this.pyramid.id);
      this.pyramid = undefined;
    }
    if (this.frustumPrimitive) {
      this.viewer.scene.primitives.remove(this.frustumPrimitive);
      this.frustumPrimitive = undefined;
    }
    if (this.debugModelMatrixPrimitive) {
      this.viewer.scene.primitives.remove(this.debugModelMatrixPrimitive);
      this.debugModelMatrixPrimitive = undefined;
    }
  }
  clearViewershedAll() {
    this.clearViewShed();

    if (this.viewershedPolygon) {
      this.viewer.scene.primitives.remove(this.viewershedPolygon);
      this.viewershedPolygon = undefined;
    }
  }
  addVisualPyramid() {
    let options = this.ViewShedOptions;
    let position = options.viewPosition;
    let visualRange = Number(options.visualRange);
    let transform = Cesium.Transforms.eastNorthUpToFixedFrame(position);
    this.debugModelMatrixPrimitive = this.viewer.scene.primitives.add(
      new Cesium.DebugModelMatrixPrimitive({
        modelMatrix: transform,
        length: 5.0,
      })
    );
    const halfClock = options.horizontalViewAngle / 2;
    const halfCone = options.verticalViewAngle / 2;
    const pitch = Cesium.Math.toDegrees(options.pitch);
    const ellipsoid = new Cesium.EllipsoidGraphics({
      radii: new Cesium.Cartesian3(visualRange, visualRange, visualRange),
      minimumClock: Cesium.Math.toRadians(90 - options.direction - halfClock),
      maximumClock: Cesium.Math.toRadians(90 - options.direction + halfClock),
      minimumCone: Cesium.Math.toRadians(90 - pitch - halfCone),
      maximumCone: Cesium.Math.toRadians(90 - pitch + halfCone),
      fill: false,
      outline: true,
      subdivisions: 256,
      stackPartitions: 64,
      slicePartitions: 64,
      outlineColor: Cesium.Color.YELLOWGREEN.withAlpha(0.5),
    });
    const pyramidEntity = new Cesium.Entity({
      position: position,
      ellipsoid,
    });
    this.pyramid = this.viewer.entities.add(pyramidEntity);
  }
  setLightCamera() {
    if (!this.lightCamera) {
      this.lightCamera = new Cesium.Camera(this.viewer.scene);
    }
    let options = this.ViewShedOptions;
    let visualRange = Number(options.visualRange);
    this.lightCamera.position = options.viewPosition;
    this.lightCamera.frustum.near = 0.1;
    this.lightCamera.frustum.far = visualRange;
    const hr = Cesium.Math.toRadians(options.horizontalViewAngle);
    const vr = Cesium.Math.toRadians(options.verticalViewAngle);
    this.lightCamera.frustum.aspectRatio =
      (visualRange * Math.tan(hr / 2) * 2) /
      (visualRange * Math.tan(vr / 2) * 2);
    this.lightCamera.frustum.fov = hr > vr ? hr : vr;
    this.lightCamera.setView({
      destination: options.viewPosition,
      orientation: {
        heading: Cesium.Math.toRadians(options.direction || 0),
        pitch: options.pitch || 0,
        roll: 0,
      },
    });
  }
  createFrustum() {
    const scratchRight = new Cesium.Cartesian3();
    const scratchRotation = new Cesium.Matrix3();
    const scratchOrientation = new Cesium.Quaternion();
    const direction = this.lightCamera.directionWC;
    const up = this.lightCamera.upWC;
    let right = this.lightCamera.rightWC;
    right = Cesium.Cartesian3.negate(right, scratchRight);
    let rotation = scratchRotation;
    Cesium.Matrix3.setColumn(rotation, 0, right, rotation);
    Cesium.Matrix3.setColumn(rotation, 1, up, rotation);
    Cesium.Matrix3.setColumn(rotation, 2, direction, rotation);
    let orientation = Cesium.Quaternion.fromRotationMatrix(
      rotation,
      scratchOrientation
    );
    let instanceOutline = new Cesium.GeometryInstance({
      geometry: new Cesium.FrustumOutlineGeometry({
        frustum: this.lightCamera.frustum,
        origin: this.ViewShedOptions.viewPosition,
        orientation: orientation,
      }),
      id: "视椎体轮廓线" + Math.random().toString(36).substr(2),
      attributes: {
        color: Cesium.ColorGeometryInstanceAttribute.fromColor(
          new Cesium.Color(0.0, 1.0, 0.0, 1.0)
        ),
        show: new Cesium.ShowGeometryInstanceAttribute(true),
      },
    });
    this.frustumPrimitive = this.viewer.scene.primitives.add(
      new Cesium.Primitive({
        geometryInstances: instanceOutline,
        appearance: new Cesium.PerInstanceColorAppearance({
          flat: true,
          translucent: false,
          closed: true,
        }),
      })
    );
  }
  createPoint(firstPos, secondPos) {
    let entity4FirstPos = new Cesium.Entity({
      name: "firstPos",
      show: true,
      position: firstPos,
      point: {
        show: true,
        pixelSize: 20,
        color: Cesium.Color.RED,
        outlineColor: Cesium.Color.YELLOW,
        outlineWidth: 5,
      },
      description: `
	            <p>这是绘制的视椎体起点</p>`,
    });
    this.viewer.entities.add(entity4FirstPos);
    let entity4SecondPos = new Cesium.Entity({
      name: "secondPos",
      show: true,
      position: secondPos,
      point: {
        show: true,
        pixelSize: 30,
        color: Cesium.Color.YELLOW,
        outlineColor: Cesium.Color.RED,
        outlineWidth: 8,
      },
      description: `
	            <p>这是绘制的视椎体视角终点</p>`,
    });
    this.viewer.entities.add(entity4SecondPos);
  }
  //绘制可视域
  add(positionArr) {
    // console.log(positionArr)
    let polygon = new Cesium.PolygonGeometry({
      polygonHierarchy: new Cesium.PolygonHierarchy(
        Cesium.Cartesian3.fromDegreesArray(positionArr)
      ),
      height: 0.0,
      extrudedHeight: 0.0,
      vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
      stRotation: 0.0, // 纹理的旋转坐标（以弧度为单位）,正旋转是逆时针方向
      ellipsoid: Cesium.Ellipsoid.WGS84,
      granularity: Cesium.Math.RADIANS_PER_DEGREE, // 每个纬度和经度之间的距离（以弧度为单位）,确定缓冲区中的位置数
      perPositionHeight: false, // 每个位置点使用的高度
      closeTop: true,
      closeBottom: true,
      // NONE 与椭圆表面不符的直线;GEODESIC 遵循测地路径;RHUMB	遵循大黄蜂或恶魔般的道路。
      arcType: Cesium.ArcType.GEODESIC, // 多边形边缘线型
    });

    let polygonInstance = new Cesium.GeometryInstance({
      geometry: polygon,
      name: "ViewershedPolygon",
      attributes: {
        color: Cesium.ColorGeometryInstanceAttribute.fromColor(
          Cesium.Color.BLUE.withAlpha(0.6)
        ),
        show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏
      },
    });
    this.viewershedPolygon = this.viewer.scene.primitives.add(
      new Cesium.GroundPrimitive({
        geometryInstances: polygonInstance,
        appearance: new Cesium.EllipsoidSurfaceAppearance({
          aboveGround: true,
          material: new Cesium.Material({
            fabric: {
              type: "Image",
              uniforms: {
                image: this.returnImgae(),
              },
            },
          }),
        }),
      })
    );
  }
  drawViewershed(precision, opt = {}) {
    const pos = this.cartesian3ToDegree(this.ViewShedOptions.viewPosition);
    const radius = this.ViewShedOptions.visualRange;
    const direction = this.ViewShedOptions.direction;
    // console.log(pos, radius, direction)
    let boundary = this.computeBoundaryOptions(pos, radius, direction);
    const bbox = boundary.bbox;

    let mask = turf.polygon([boundary.boundaryPoints]);
    const dis = this.ViewShedOptions.visualRange / (precision * 1000);
    let gridPoints = turf.pointGrid(bbox, dis, {
      mask: mask,
    });

    let pointsResult = this.createTargetPoints(gridPoints, dis, pos);
    // console.log(pointsResult)
    let variogram = kriging.train(
      pointsResult.values,
      pointsResult.lngs,
      pointsResult.lats,
      "exponential",
      0,
      100
    );
    let grid = kriging.grid([boundary.boundaryPoints], variogram, dis / 1000);

    let colors = [
      "#ff000080",
      "#ff000080",
      "#ff000080",
      "#ff000080",
      "#ff000080",
      "#ff000080",
      "#00ff0080",
      "#00ff0080",
      "#00ff0080",
      "#00ff0080",
      "#00ff0080",
      "#00ff0080",
    ];
    if (opt.visibleColor) {
      //可视区域颜色,16进制颜色+两位透明度
      colors[0] =
        colors[1] =
        colors[2] =
        colors[3] =
        colors[4] =
        colors[5] =
          opt.visibleColor;
    }
    if (opt.invisibleColor) {
      //不可视区域颜色,16进制颜色+两位透明度
      colors[6] =
        colors[7] =
        colors[8] =
        colors[9] =
        colors[10] =
        colors[11] =
          opt.invisibleColor;
    }

    this.canvasEle.width = 3840;
    this.canvasEle.height = 2160;
    kriging.plot(
      this.canvasEle,
      grid,
      [bbox[0], bbox[2]],
      [bbox[1], bbox[3]],
      colors
    );
    this.add(boundary.positionArr);

    return {
      mask: boundary.boundaryPoints,
      pointsResult: pointsResult,
    };
  }
  computeBoundaryOptions(pos, radius, angle) {
    let Ea = 6378137; //   赤道半径
    let Eb = 6356725; // 极半径
    const lng = pos[0],
      lat = pos[1];
    const bbox = [lng, lat, lng, lat]; //[minX, minY, maxX, maxY]
    let positionArr = [];
    let boundaryPoints = [];
    positionArr.push(lng, lat);
    boundaryPoints.push([lng, lat]);
    //正北是0°
    let s = this.ViewShedOptions.horizontalViewAngle / 2;
    let start = angle + s > 360 ? angle - s - 360 : angle - s;
    let end = start + s * 2;
    for (let i = start; i <= end; i++) {
      let dx = radius * Math.sin((i * Math.PI) / 180.0);
      let dy = radius * Math.cos((i * Math.PI) / 180.0);
      let ec = Eb + ((Ea - Eb) * (90.0 - lat)) / 90.0;
      let ed = ec * Math.cos((lat * Math.PI) / 180);
      let BJD = lng + ((dx / ed) * 180.0) / Math.PI;
      let BWD = lat + ((dy / ec) * 180.0) / Math.PI;
      positionArr.push(BJD, BWD);
      boundaryPoints.push([BJD, BWD]);
      this.refreshBBox(bbox, BJD, BWD);
    }
    boundaryPoints.push([lng, lat]);
    return {
      positionArr,
      boundaryPoints,
      bbox,
    };
  }
  /**
   * 更新外围矩形 Bbox
   * @param {Array} result 外围矩形Bbox-[minX, minY, maxX, maxY]
   * @param {Number} x 经度
   * @param {Number} y 纬度
   */
  refreshBBox(result, x, y) {
    result[0] = x < result[0] ? x : result[0];
    result[1] = y < result[1] ? y : result[1];
    result[2] = x > result[2] ? x : result[2];
    result[3] = y > result[3] ? y : result[3];
  }
  /**
   * 插值点用射线判断通视性
   * @param {*} gridPoints 网格点
   * @param {*} step 步长，可以理解成是精度
   * @param {*} sourcePos 视域分析起点
   * @returns kriging插值所需的参数对象{ values:[], lngs:[], lats:[]}
   */
  createTargetPoints(gridPoints, step, sourcePos) {
    let positionArr = [];
    let objectsToExclude = [
      this.frustumPrimitive,
      this.pyramid,
      this.debugModelMatrixPrimitive,
    ];
    let values = [],
      lngs = [],
      lats = [];
    let height = this.getHeight(sourcePos[0], sourcePos[1], objectsToExclude);
    positionArr.push({
      x: sourcePos[0],
      y: sourcePos[1],
      z: height,
    });
    let viewPoint = this.ViewShedOptions.viewPosition;
    for (let index = 0; index < gridPoints.features.length; index++) {
      const feature = gridPoints.features[index];
      const coords = feature.geometry.coordinates;
      const x = coords[0],
        y = coords[1];
      let h = this.getHeight(x, y, objectsToExclude);
      let endPoint = Cesium.Cartesian3.fromDegrees(x, y, h);
      let direction = Cesium.Cartesian3.normalize(
        Cesium.Cartesian3.subtract(
          endPoint,
          viewPoint,
          new Cesium.Cartesian3()
        ),
        new Cesium.Cartesian3()
      );
      // 建立射线
      let ray = new Cesium.Ray(viewPoint, direction);
      let result = this.viewer.scene.pickFromRay(ray, objectsToExclude); // 计算交互点，返回第一个
      if (result && result.position) {
        let buffer = this.ReturnDistance(endPoint, result.position);
        // let M_color = Cesium.Color.GREEN;
        if (buffer > step) {
          // M_color = Cesium.Color.RED;
          values.push(0);
        } else {
          values.push(1);
        }
        lngs.push(x);
        lats.push(y);
        // this.viewer.entities.add(
        //   new Cesium.Entity({
        //     name: "插值点",
        //     show: true,
        //     position: endPoint,
        //     point: {
        //       show: true,
        //       pixelSize: 10,
        //       color: M_color,
        //       outlineWidth: 2,
        //       outlineColor: Cesium.Color.YELLOW,
        //     },
        //   })
        // );
      }
    }
    return {
      values,
      lngs,
      lats,
    };
  }
  /**
   * canvas转image图片
   * @returns base64图片
   */
  returnImgae() {
    return this.canvasEle.toDataURL("image/png");
  }
  //--------可视域分析-end--------------------------------------------
}
var CreateRemindertip = function (arr, position, show) {
  let tooltip = document.getElementById("toolTip");
  let style, _x, _y, _color;
  if (arr && typeof arr === "object") {
    style = arr;
  }
  if (style && style.origin) {
    style.origin === "center" && ((_x = 15), (_y = -12));
    style.origin === "top" && ((_x = 15), (_y = -44));
    style.origin === "bottom" && ((_x = 15), (_y = 20));
  } else {
    (_x = 15), (_y = 20);
  }
  if (style && style.color) {
    style.color === "white" &&
      (_color = "background: rgba(255, 255, 255, 0.8);color: black;");
    style.color === "black" &&
      (_color = "background: rgba(0, 0, 0, 0.5);color: white;");
    style.color === "yellow" &&
      (_color =
        "color: black;background-color: #ffcc33;border: 1px solid white;");
  } else {
    _color = "background: rgba(0, 0, 0, 0.5);color: white;";
  }
  if (!tooltip) {
    const viewerDom = document.getElementsByClassName("cesium-viewer")[0];
    let elementbottom = document.createElement("div");
    viewerDom.append(elementbottom);
    let html =
      '<div id="toolTip" style="display: none;pointer-events: none;position: absolute;z-index: 1000;opacity: 0.8;border-radius: 4px;padding: 4px 8px;white-space: nowrap;font-family:黑体;color:white;font-weight: bolder;font-size: 14px;' +
      _color +
      '"></div>';
    viewerDom.insertAdjacentHTML("beforeend", html);
    tooltip = document.getElementById("toolTip");
  }
  if (show) {
    tooltip.innerHTML = arr;
    tooltip.style.left = position.x + _x + "px";
    tooltip.style.top = position.y + _y + "px";
    tooltip.style.display = "block";
  } else {
    tooltip.style.display = "none";
  }
  return {
    tooltip: tooltip,
    style: style,
    showAt: function (position, text) {
      this.tooltip.innerHTML = text;
      if (this.style && this.style.origin) {
        this.style.origin === "center" &&
          ((_x = 15), (_y = -this.tooltip.offsetHeight / 2));
        this.style.origin === "top" &&
          ((_x = 15), (_y = -this.tooltip.offsetHeight - 20));
        this.style.origin === "bottom" && ((_x = 15), (_y = 20));
      } else {
        (_x = 15), (_y = -this.tooltip.offsetHeight / 2);
      }
      this.tooltip.style.left = position.x + _x + "px";
      this.tooltip.style.top = position.y + _y + "px";
      this.tooltip.style.display = "block";
    },
    show: function (show) {
      if (show) {
        this.tooltip.style.display = "block";
      } else {
        this.tooltip.style.display = "none";
      }
    },
  };
};

var setSessionid = function (num) {
  let len = num || 32;
  let chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";
  let maxPos = chars.length;
  let pwd = "";
  for (let i = 0; i < len; i++) {
    pwd += chars.charAt(Math.floor(Math.random() * maxPos));
  }
  return pwd;
};

/**
 * 创建贴地多边形
 * @param {object} viewer viewer
 * @param {Array} resultList
 * @param {{id:String,color:object,outlineColor:object,outlineWidth:number}} options {id，填充颜色，轮廓线颜色，轮廓线宽度}
 * @param {Function} callback 携带创建的多边形对象
 */
const CreatePolygonOnGround = function (viewer, resultList, options, callback) {
  if (!viewer) throw new Error("no viewer object!");
  options = options || {};
  let id = options.id || setSessionid(); //Polygon的id
  if (viewer.entities.getById(id))
    throw new Error("the id parameter is an unique value");
  let color = options.color || Cesium.Color.RED; //Polygon的填充色
  let outlineColor = options.outlineColor || color.withAlpha(1); //Polygon的轮廓线颜色
  let outlineWidth = options.outlineWidth || 2; //Polygon的轮廓线宽度
  const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
  let toolTip = "左键点击开始绘制";
  let anchorpoints = [];
  let polygon = undefined;
  let drawStatus = true;
  handler.setInputAction(function (event) {
    let pixPos = event.position;
    let cartesian = getCatesian3FromPX(viewer, pixPos);
    if (isNaN(cartesian.x) || isNaN(cartesian.y) || isNaN(cartesian.z)) {
      ElMessage({
        message: "此点无效，重新选点！",
        type: "info",
        duration: 1000,
      });
      return;
    }
    if (anchorpoints.length == 0) {
      toolTip = "左键添加第二个点";
      anchorpoints.push(cartesian);
      let linePoints = new Cesium.CallbackProperty(function () {
        let verPoints = anchorpoints.concat([anchorpoints[0]]);
        return verPoints;
      }, false);
      let dynamicPositions = new Cesium.CallbackProperty(function () {
        return new Cesium.PolygonHierarchy(anchorpoints);
      }, false);
      polygon = viewer.entities.add({
        name: "Polygon",
        id: id,
        polyline: {
          positions: linePoints,
          width: outlineWidth,
          material: outlineColor,
          clampToGround: true,
        },
        polygon: {
          heightReference: Cesium.HeightReference.None,
          hierarchy: dynamicPositions,
          material: color,
        },
      });
      polygon.GeoType = "Polygon";
    } else {
      toolTip = "左键添加点，Ctrl+Z回退，右键完成绘制";
    }
    anchorpoints.push(cartesian);
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
  handler.setInputAction(function (movement) {
    let endPos = movement.endPosition;
    CreateRemindertip(toolTip, endPos, true);
    if (Cesium.defined(polygon)) {
      let cartesian = getCatesian3FromPX(viewer, endPos);
      if (isNaN(cartesian.x) || isNaN(cartesian.y) || isNaN(cartesian.z)) {
        ElMessage({
          message: "此点无效，重新选点！",
          type: "info",
          duration: 1000,
        });
        return;
      }
      anchorpoints.pop();
      anchorpoints.push(cartesian);
    }
    if (anchorpoints.length === 3) {
      polygon.polygon.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND;
    }
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  handler.setInputAction(function (event) {
    waitTip = ElMessage({
      message: "正在执行分析...",
      type: "success",
      duration: 0,
      offset: 50,
    });

    anchorpoints.pop();

    polygon.pottingPoint = anchorpoints;

    resultList.push(polygon);

    handler.destroy();

    CreateRemindertip(toolTip, event.position, false);
    drawStatus = false;

    if (typeof callback == "function") callback(polygon);
  }, Cesium.ScreenSpaceEventType.RIGHT_DOWN);
  //Ctrl + Z回退
  document.onkeydown = function (event) {
    if (event.ctrlKey && window.event.keyCode == 90) {
      if (!drawStatus) {
        return false;
      }
      anchorpoints.pop();
      if (anchorpoints.length == 2) {
        toolTip = "左键添加第二个点";
      }
    }
  };
};

var getCatesian3FromPX = function (viewer, px) {
  let picks = viewer.scene.drillPick(px);
  let cartesian = null;
  let isOn3dtiles = false,
    isOnTerrain = false;
  // drillPick
  for (let i in picks) {
    let pick = picks[i];
    if (
      (pick && pick.primitive instanceof Cesium.Cesium3DTileFeature) ||
      (pick && pick.primitive instanceof Cesium.Cesium3DTileset) ||
      (pick && pick.primitive instanceof Cesium.Model)
    ) {
      //模型上拾取
      isOn3dtiles = true;
    }
    // 3dtilset
    if (isOn3dtiles) {
      viewer.scene.pick(px); // pick
      cartesian = viewer.scene.pickPosition(px);
      if (cartesian) {
        let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
        if (cartographic.height < 0) cartographic.height = 0;
        let lon = Cesium.Math.toDegrees(cartographic.longitude),
          lat = Cesium.Math.toDegrees(cartographic.latitude),
          height = cartographic.height;
        cartesian = transformWGS84ToCartesian(viewer, {
          lng: lon,
          lat: lat,
          alt: height,
        });
      }
    }
  }
  // 地形
  let boolTerrain =
    viewer.terrainProvider instanceof Cesium.EllipsoidTerrainProvider;
  // Terrain
  if (!isOn3dtiles && !boolTerrain) {
    let ray = viewer.scene.camera.getPickRay(px);
    if (!ray) return null;
    cartesian = viewer.scene.globe.pick(ray, viewer.scene);
    isOnTerrain = true;
  }
  // 地球
  if (!isOn3dtiles && !isOnTerrain && boolTerrain) {
    cartesian = viewer.scene.camera.pickEllipsoid(
      px,
      viewer.scene.globe.ellipsoid
    );
  }
  if (cartesian) {
    let position = transformCartesianToWGS84(viewer, cartesian);
    if (position.alt < 0) {
      cartesian = transformWGS84ToCartesian(viewer, position, 0.1);
    }
    return cartesian;
  }
  return false;
};

/***
 * 坐标转换 84转笛卡尔
 * @param {Object} {lng,lat,alt} 地理坐标
 * @return {Object} Cartesian3 三维位置坐标
 */
var transformWGS84ToCartesian = function (viewer, position, alt) {
  return position
    ? Cesium.Cartesian3.fromDegrees(
        position.lng || position.lon,
        position.lat,
        (position.alt = alt || position.alt),
        Cesium.Ellipsoid.WGS84
      )
    : Cesium.Cartesian3.ZERO;
};

/***
 * 坐标转换 笛卡尔转84
 * @param {Object} Cartesian3 三维位置坐标
 * @return {Object} {lng,lat,alt} 地理坐标
 */
var transformCartesianToWGS84 = function (viewer, cartesian) {
  let ellipsoid = Cesium.Ellipsoid.WGS84;
  let cartographic = ellipsoid.cartesianToCartographic(cartesian);
  return {
    lng: Cesium.Math.toDegrees(cartographic.longitude),
    lat: Cesium.Math.toDegrees(cartographic.latitude),
    alt: cartographic.height,
  };
};

/**
 * 笛卡尔坐标数组转WGS84
 * @param {Array} cartesianList 笛卡尔坐标数组
 * @returns {Array} WGS84经纬度坐标数组
 */
var Cartesian3ListToWGS84 = function (cartesianList) {
  let ellipsoid = Cesium.Ellipsoid.WGS84;
  let result = [];
  for (let index = 0; index < cartesianList.length; index++) {
    const cartesian = cartesianList[index];
    let cartographic = ellipsoid.cartesianToCartographic(cartesian);
    result.push({
      lng: Cesium.Math.toDegrees(cartographic.longitude),
      lat: Cesium.Math.toDegrees(cartographic.latitude),
      alt: cartographic.height,
    });
  }
  return result;
};

export default AnalysisTools;
